﻿using Castle.Core;
using Castle.Core.Internal;
using Castle.MicroKernel.Registration;
using System;
using System.Linq;

namespace Inovout.Components
{
    public static class ComponentRegistrationExtensions
    {
        public static ComponentRegistration<TService> IsGenericParameterConstraints<TService>(this ComponentRegistration<TService> componentRegistration) where TService : class
        {
            return IsGenericParameterConstraints(componentRegistration, Supports);
        }
        public static ComponentRegistration<TService> IsGenericParameterConstraints<TService>(this ComponentRegistration<TService> componentRegistration, Func<Type, ComponentModel, bool> supports) where TService : class
        {
            componentRegistration.ExtendedProperties(
                        Property.ForKey(Constants.GenericServiceStrategy).Eq(
                        new DelegateServiceStrategy(supports))
                    );
            return componentRegistration;
        }
        private static bool Supports(Type serviceType, ComponentModel componentModel)
        {
            var serviceGenericArguments = serviceType.GetGenericArguments();
            var serviceInComponentGenericArguments = componentModel.Implementation.GetInterface(serviceType.Name).GetGenericArguments();
            var componentGenericArguments = componentModel.Implementation.GetGenericArguments();
            for (int i = 0; i < serviceGenericArguments.Length; i++)
            {
                //通过ServiceType泛型参数索引获取实现类对应的接口索引
                //再通过接口索引获取实现类约束
                //检测约束
                Type componentGenericArgument = componentGenericArguments.Single(t => 
                    t.Equals(serviceInComponentGenericArguments[i]));
                if (componentGenericArgument.GetGenericParameterConstraints()
                    .Any(t => !t.IsAssignableFrom(serviceGenericArguments[i])))
                {
                    return false;
                }
            }
            return true;
        }

    }
}
